package es.unex.meigas.dataObjects;

import es.unex.meigas.exceptions.UnsupportedOutputChannelException;
import es.unex.meigas.rasterWrappers.GridExtent;

/**
 * An OutputFactory defines how new data objects (layers and tables) are created.
 * Method in this class are called from geoalgorithms to create output objects
 * @author Victor Olaya volaya@unex.es
 *
 */
public abstract class OutputFactory {

	private int m_iCount = 0;

	/**
	 * Use this method to create a new VectorMemoryDriver that can be used
	 * to generate new vector layers as output from the geo-algorithm
	 *
	 * @param sName the name of the layer
	 * @param iShapeType the type of shapes in the layer
	 * @param types the data type of the fields
	 * @param sFields the name of the fields in the attributes table
	 * @param sFilename the filename associated to the output layer
	 * @param crs An object with information to set the CRS of
     * this layer (i.e. a string with a EPSG code)
	 * @return an empty vector layer
	 */
	public abstract IVectorLayer getNewVectorLayer(String sName,
														 int iShapeType,
														 Class[] types,
														 String[] sFields,
														 IOutputChannel channel,
														 Object crs)
								throws UnsupportedOutputChannelException;


	/**
	 * Use this method to create a new raster layer as output from the geo-algorithm.
	 * Only the extent is taken from m_GridExtent, but not the cellsize,
	 * which is taken from the input layer. The extent is adjusted to fit into
	 * the layer, so that same extent can be used to query it without interpolating
	 * data. This should be used when interpolation must be performed afterwards on
	 * the resulting layer and not while reading the input one, like, for example,
	 * when calculating a flow acc grid from a DEM. The layer is added to the output
	 * objects list and resampled at the end of the process, in order to match user-defined
	 * raster characteristics.
	 *
	 * @param iDataType the type of data in the layer
	 * @param layer a base layer used to define raster layer characteristics.
	 * @param iBands the number of bands of the layer
	 * @param outputGridExtent The grid extent of the output layer. This will be adjusted
	 * to fit into the given layer
	 * @param sFilename the filename associated to the output layer
	 * @param crs An object with information to set the CRS of
     * this layer (i.e. a string with a EPSG code)
	 * @return a zeroed raster layer
	 */
	public IRasterLayer getNewRasterLayer(String sName,
														int iDataType,
														IRasterLayer layer,
														int iBands,
														GridExtent outputGridExtent,
														IOutputChannel channel,
														Object crs)
							throws UnsupportedOutputChannelException{

		double iMinX, iMinY, iMaxX, iMaxY;
		double dMinX, dMinY;
		double dMinX2, dMinY2, dMaxX2, dMaxY2;
		double dCellSize;
		GridExtent ge = new GridExtent();

		dMinX = layer.getLayerGridExtent().getXMin();
		dMinY = layer.getLayerGridExtent().getYMin();
		dCellSize = layer.getLayerGridExtent().getCellSize();

		iMinX = Math.floor( (outputGridExtent.getXMin() - dMinX) / dCellSize);// - 1;
		iMaxX = Math.ceil( (outputGridExtent.getXMax() - dMinX) / dCellSize) ;//+ 1;
		iMinY = Math.floor( (outputGridExtent.getYMin() - dMinY) / dCellSize);// - 1;
		iMaxY = Math.ceil( (outputGridExtent.getYMax() - dMinY) / dCellSize) ;//+ 1;

		dMinX2 = dMinX + iMinX *  dCellSize;
		dMinY2 = dMinY + iMinY *  dCellSize;
		dMaxX2 = dMinX + iMaxX *  dCellSize;
		dMaxY2 = dMinY + iMaxY *  dCellSize;

		ge.setCellSize(dCellSize);
		ge.setXRange(dMinX2, dMaxX2);
		ge.setYRange(dMinY2, dMaxY2);

		return getNewRasterLayer(sName, iDataType,
								ge, iBands, channel, crs);

	}

	/**
	 * Use this method to create a new raster layer as output
	 * from the geo-algorithm.
	 * The characteristics of the raster layer (extent and cellsize) are
	 * taken from the extent parameter.
	 *
	 * @param sName the name of the layer
	 * @param iDataType the type of data in the layer
	 * @param extent the GridExtent to use for the driver
	 * @param iBands the number of bands of the new layer
	 * @param sFilename the filename associated with this layer
	 * @param crs An object with information to set the CRS of
     * this layer (i.e. a string with a EPSG code)
	 * @return a zeroed RasterMemoryDriver
	 */
	public abstract IRasterLayer getNewRasterLayer(String sName,
														  int iDataType,
														  GridExtent extent,
														  int iBands,
														  IOutputChannel channel,
														  Object crs)
							throws UnsupportedOutputChannelException;

	 /**
	  * Use this method to create a new table.
	  *
	  * @param sName the name of the table
	  * @param types the data type of the fields
	  * @param sFields The names of the fields in the table
	  * @param sFilename the filename associated to the table
	  * @return a new empty table object
	  */
	public abstract ITable getNewTable(String sName,
												  Class [] types,
												  String[] sFields,
												  IOutputChannel channel)
							throws UnsupportedOutputChannelException;



	/**
	 * Returns the extensions supported by this factory
	 * for creating raster layers. If a filename with an extension not found in this list
	 * of extensions is used to create a raster layer, the default extension (the first
	 * one of the list) will be added to the filename when creating that layer.
	 * @return the list of supported extensions for raster layers
	 */
	public abstract String[] getRasterLayerOutputExtensions();

	/**
	 * Returns the extensions supported by this factory
	 * for creating vector layers. If a filename with an extension not found in this list
	 * of extensions is used to create a vector layer, the default extension (the first
	 * one of the list) will be added to the filename when creating that layer.
	 * @return the list of supported extensions for vector layers
	 */
	public abstract String[] getVectorLayerOutputExtensions();

	/**
	 * Returns the extensions supported by this factory
	 * for creating raster layers. If a filename with an extension not found in this list
	 * of extensions is used to create a raster layer, the default extension (the first
	 * one of the list) will be added to the filename when creating that layer.
	 * @return the list of supported extensions for raster layers
	 */
	public abstract String[] getTableOutputExtensions();


	/**
	 * Returns the default CRS for new layers. This will be used when the geoalgorithm
	 * generates new layers but does not take any other layer as input, so the CRS cannot
	 * be defined from the inputs
	 * @return an object containing information about the default CRS (i.e. a String with the
	 * EPSG code of the CRS)
	 */
	public abstract Object getDefaultCRS();


}
